package encaps.utils;

import encaps.action.Action;
import encaps.action.ActionContext;
import encaps.action.ActionFactory;
import encaps.entities.Grant;
import static encaps.resources.ActionFactories.*;
import encaps.resources.Labels;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;

public class RequestParser {

    private String defaultActionFactory;
    private Map<String, ActionFactory> actionFactories;

    public RequestParser() throws InitializationException {
        actionFactories = new HashMap<String, ActionFactory>();

        try {
            //Загружаем xml-файл как ресурс
            Class c = getClass();
            InputStream in = c.getResourceAsStream(CONFIGURATION_FILE_PATH);

            //Парсим xml-файл
            SAXBuilder builder = new SAXBuilder();
            Document doc = builder.build(in);

            Element root = doc.getRootElement();

            //Установка фабрики по умолчанию

            Element defaultFactoryElement = root.getChild(DEFAULT_FACTORY);
            defaultActionFactory =
                    defaultFactoryElement.getChild(NAME).getValue().trim();

            //Заполнение карты фабрик
            List factories = root.getChild(FACTORY_LIST).getChildren(FACTORY);
            for (Object obj : factories) {
                Element factoryElement = (Element) obj;
                String name = factoryElement.getChild(NAME).getValue().trim();
                String className = factoryElement.getChild(CLASS).getValue().trim();
                String requiredGrantName = factoryElement.getChild(GRANT).getValue().trim();

                Grant requiredGrant;
                if (StringUtil.isEmpty(requiredGrantName)) {
                    requiredGrant = null;
                } else {
                    requiredGrant = new Grant(requiredGrantName);
                }
                //Создаем экземпляр фабрики Action-ов
                Class factoryClass = Class.forName(className);
                Constructor constructor = factoryClass.getConstructor(Grant.class);


                ActionFactory factory = (ActionFactory) constructor.newInstance(requiredGrant);

                //Добавляем фабрику в карту
                actionFactories.put(name, factory);
            }
        } catch (JDOMException ex) {
            throw new InitializationException(Labels.getLabel(Labels.REQUEST_PARSER_FILE_PARSING_ERROR_MESSAGE), ex);
        } catch (ClassNotFoundException ex) {
            throw new InitializationException(Labels.getLabel(Labels.REQUEST_PARSER_NO_SUCH_FACTORY_MESSAGE) + ex.getMessage(), ex);
        } catch (IOException ex) {
            throw new InitializationException(Labels.getLabel(Labels.REQUEST_PARSER_IO_ERROR_MESSAGE), ex);
        } catch (Exception ex) {
            throw new InitializationException(Labels.getLabel(Labels.REQUEST_PARSER_INIT_ERROR_MESSAGE), ex);
        }
    }

    public Action parseRequest(String actionName, ActionContext context) {
        if (StringUtil.isEmpty(actionName)) {
            if (StringUtil.isEmpty(defaultActionFactory)) {
                return null;
            }
            ActionFactory defaultFactory = actionFactories.get(defaultActionFactory);
            return defaultFactory.createAction(context);
        }
        ActionFactory factory = actionFactories.get(actionName);
        Action action = factory.createAction(context);
        return action;
    }

    public Action parseRequest(ActionContext context) throws SystemException {
        String actionName = context.getActionName();
        return parseRequest(actionName, context);
    }
}
